home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / corelib / ncbiprop.c < prev    next >
Text File  |  1996-07-05  |  17KB  |  638 lines

  1. /*   ncbiprop.h
  2. * ===========================================================================
  3. *
  4. *                            PUBLIC DOMAIN NOTICE                          
  5. *               National Center for Biotechnology Information
  6. *                                                                          
  7. *  This software/database is a "United States Government Work" under the   
  8. *  terms of the United States Copyright Act.  It was written as part of    
  9. *  the author's official duties as a United States Government employee and 
  10. *  thus cannot be copyrighted.  This software/database is freely available 
  11. *  to the public for use. The National Library of Medicine and the U.S.    
  12. *  Government have not placed any restriction on its use or reproduction.  
  13. *                                                                          
  14. *  Although all reasonable efforts have been taken to ensure the accuracy  
  15. *  and reliability of the software and data, the NLM and the U.S.          
  16. *  Government do not and cannot warrant the performance or results that    
  17. *  may be obtained by using this software or data. The NLM and the U.S.    
  18. *  Government disclaim all warranties, express or implied, including       
  19. *  warranties of performance, merchantability or fitness for any particular
  20. *  purpose.                                                                
  21. *                                                                          
  22. *  Please cite the author in any work or product based on this material.   
  23. *
  24. * ===========================================================================
  25. *
  26. * File Name:  ncbiprop.h
  27. *
  28. * Author:  Schuler
  29. *
  30. * Version Creation Date:   06-04-93
  31. *
  32. * $Revision: 2.12 $
  33. *
  34. * File Description:        Application Property Functions.
  35. *
  36. *        Application properties were    introduced to allow the NCBI Toolbox 
  37. *        to be implemented as a dynamic link library (DLL).  Under Windows, 
  38. *        global variables located in the DLL are not instantiated for each 
  39. *        application    instance, but instead shared by all applications having 
  40. *        a run-time linkage.  Values that might ordinarily be stored in 
  41. *        global variables can instead be saved as application properties
  42. *        (unless sharing is desired, of course).  An application property
  43. *        is simply a pointer (or other value cast to a pointer) that is
  44. *        identified by a string key.  Properties are kept in a linked list
  45. *        (sorted by key) whose head is stored in an application context block.
  46. *        The application context block is created on-demand and marked 
  47. *        with the process ID of the calling application (or it's creation
  48. *        can be forced by calling InitAppContext() at the beginning of your
  49. *        program.  The linked list of (smallish) application context 
  50. *        structures is the only thing allocated from the DLL's data space, 
  51. *        all other memory is owned by the application that called the DLL 
  52. *        is automatically freed by the system when the application terminates.
  53. *        
  54. *        If this code is not actually compiled as a DLL, but bound at link
  55. *        time to a single application in the normal way, the behavior of all
  56. *        functions will be the same.  The only difference being that the
  57. *        list of application context structures will contain exactly one item.
  58. *
  59. * Modifications:  
  60. * --------------------------------------------------------------------------
  61. * Date     Name        Description of modification
  62. * -------  ----------  -----------------------------------------------------
  63. *
  64. * ==========================================================================
  65. */
  66. #include <ncbi.h>
  67. #include <ncbiwin.h>
  68.  
  69.  
  70.  
  71.  
  72. /*    ----------------------------------------------------------------------
  73.  *    new_AppProperty            allocates/constructs an AppProperty struct
  74.  *    delete_AppProperty        deallocates/destructs an AppProperty struct
  75.  *
  76.  *    Created: 
  77.  *        06-04-93 Schuler
  78.  *    Modified:
  79.  *        00-00-00 YourName    What changes did you make?
  80.  *    ----------------------------------------------------------------------    */
  81.  
  82. typedef struct _AppProperty_
  83. {
  84.     struct _AppProperty_    *next;
  85.     char *key;
  86.     void *data;
  87. }
  88. AppProperty;
  89.  
  90. static AppProperty * new_AppProperty PROTO((const char *key, void *data));
  91. static void delete_AppProperty PROTO((AppProperty *prop));
  92.  
  93. static AppProperty * new_AppProperty (const char *key, void *data)
  94. {
  95.     AppProperty *prop = (AppProperty*)  MemNew(sizeof(AppProperty));
  96.  
  97.     ASSERT(key != NULL);
  98.     ASSERT(*key != '\0');
  99.     
  100.     if (prop != NULL)
  101.     {
  102.         if ( ! (prop->key = StrSave(key)) )
  103.             prop = (AppProperty*) MemFree(prop);
  104.         else
  105.             prop->data = data;
  106.     }
  107.     return prop;
  108. }
  109.  
  110. static void delete_AppProperty (AppProperty *prop)
  111. {
  112.     ASSERT(prop != NULL);
  113.     MemFree(prop->key);
  114.     MemFree(prop);
  115. }
  116.  
  117.  
  118.  
  119. /*    ----------------------------------------------------------------------
  120.  *    new_AppContext            allocates/constructs an AppContext struct
  121.  *    delete_AppContext        deallocates/destructs an AppContext struct
  122.  *
  123.  *  Notes:  (1) If a valid context cannot be created, the application halts.
  124.  *            (2) The memory allocated for the AppContext struct is owned by
  125.  *                the DLL and the scratch buffer is owned by the application.
  126.  *            (3) It is important that this function NOT call TRACE, Message,
  127.  *                or ErrPost (or anything else that could result in any of these
  128.  *                being called) as they use the applicaion context's scratch buffer.
  129.  *
  130.  *    Created: 
  131.  *        06-04-93 Schuler
  132.  *    Modified:
  133.  *        00-00-00 YourName    What changes did you make?
  134.  *    ----------------------------------------------------------------------    */
  135.  
  136. #define SCRATCH_SIZE_DEFAULT    (2*KBYTE)
  137.  
  138. typedef struct _AppContext_
  139. {
  140.     struct _AppContext_     *next;
  141.     struct _AppProperty_    *proplist;
  142.     long     pid;
  143.     unsigned    enums    :15;    /* number of nested enumerations in-progress */
  144.     unsigned    lock    :1;        /* if TRUE, property list is locked */
  145.     Nlm_sizeT    scratch_size;
  146.     void    *scratch;
  147. }
  148. AppContext;
  149.  
  150.         /* this is the only global variable in this file: */
  151. static AppContext * g_appList;    /* Application Context List */
  152.  
  153. static AppContext * new_AppContext PROTO((long pid));
  154. static void delete_AppContext PROTO((AppContext *prop));
  155. INLINE static void  AppContext_Lock PROTO((AppContext *context));
  156. INLINE static void  AppContext_Unlock PROTO((AppContext *context));
  157. INLINE static unsigned  AppContext_IsLocked PROTO((AppContext *context));
  158.  
  159.  
  160. static AppContext * new_AppContext (long pid)
  161. {
  162.     AppContext *context = (AppContext*) dll_Malloc(sizeof(AppContext));
  163.     
  164.     if (context == NULL)
  165.         AbnormalExit(1);
  166.         
  167.     memset((void*)context,0,sizeof(struct _AppContext_));
  168.     context->pid = pid;
  169.     context->scratch_size = SCRATCH_SIZE_DEFAULT;
  170.     context->scratch = Malloc(SCRATCH_SIZE_DEFAULT);
  171.     if (context->scratch == NULL)
  172.         AbnormalExit(1);    
  173.     return context;
  174. }
  175.  
  176. static void delete_AppContext (AppContext *context)
  177. {
  178.     AppProperty *p1, *p2;
  179.     
  180.     ASSERT(context != NULL);
  181.     
  182.     for (p1=context->proplist; p1; p1=p2)
  183.     {
  184.         p2 = p1->next;
  185.         delete_AppProperty(p1);
  186.     }
  187.     Free(context->scratch);
  188.     dll_Free(context);
  189. }
  190.  
  191. static INLINE void AppContext_Lock (AppContext *context)
  192. {
  193.     ASSERT(context->lock==0);
  194.     context->lock = 1;
  195. }
  196.  
  197. static INLINE void AppContext_Unlock (AppContext *context)
  198. {
  199.     ASSERT(context->lock==1);
  200.     context->lock = 0;
  201. }
  202.  
  203. static INLINE unsigned AppContext_IsLocked (AppContext *context)
  204. {
  205.     return context->lock;
  206. }
  207.  
  208.  
  209.  
  210. /*    ----------------------------------------------------------------------
  211.  *    InitAppContext -- Initializes a context struct for current application.
  212.  *
  213.  *  Notes:  
  214.  *        If a valid context cannot be created, the application halts. 
  215.  *        Although it is not strictly necessary to call InitAppContext() as
  216.  *        contexts are created on-demand, calling it once at the beginning
  217.  *        of the program may reduce heap fragmentation.
  218.  *
  219.  *    Created: 
  220.  *        06-04-93 Schuler
  221.  *    Modified:
  222.  *        00-00-00 YourName    What changes did you make?
  223.  *
  224.  *    ----------------------------------------------------------------------    */
  225.  
  226. /* helper functions for internal use only */
  227. AppContext *GetAppContext PROTO((void));
  228. char * GetScratchBuffer PROTO((void));
  229. Nlm_sizeT GetScratchBufferSize PROTO((void));
  230.  
  231.  
  232. void LIBCALL Nlm_InitAppContext ()
  233. {
  234.     GetAppContext ();
  235. }
  236.  
  237.  
  238. AppContext *GetAppContext (void)
  239. {
  240.     long pid = Nlm_GetAppProcessID();
  241.     AppContext *p1, *p2;
  242.     AppContext *app;
  243.     
  244.     /*
  245.      *    First we scan the list of contexts for one with the current
  246.      *    application's process ID.
  247.      */
  248.     for (p1=g_appList,p2=NULL; p1; p1=p1->next)
  249.     {
  250.         if (p1->pid == pid) return p1;
  251.         if (p1->pid > pid) break;
  252.         p2 = p1;
  253.     }
  254.     
  255.     /* 
  256.      *    If we reach this point, the context for current does not 
  257.      *    exist yet, so we need to create one and link it into the list.
  258.      */
  259.     app = new_AppContext(pid);
  260.  
  261.     if (p2 == NULL)     
  262.         g_appList = app;
  263.     else  
  264.         p2->next = app;    
  265.     app->next = p1;
  266.     return app;
  267. }
  268.  
  269. char * GetScratchBuffer ()
  270. {
  271.     return (char *) GetAppContext()->scratch;
  272. }
  273.  
  274. Nlm_sizeT GetScratchBufferSize ()
  275. {
  276.     return GetAppContext()->scratch_size;
  277. }
  278.  
  279.  
  280.  
  281. /*    ----------------------------------------------------------------------
  282.  *    ReleaseAppContext -- frees application context struct for current app.
  283.  *
  284.  *    Notes:
  285.  *        For most platforms, memory will be recovered automatically by the
  286.  *        operating system.  However, since we cannot guarantee this for
  287.  *        all systems, it might be wise to call ReleaseAppContext() once
  288.  *        just before the application exits.
  289.  *
  290.  *    Created: 
  291.  *        06-04-93 Schuler
  292.  *    Modified:
  293.  *
  294.  *    ----------------------------------------------------------------------    */
  295.  
  296. void LIBCALL Nlm_ReleaseAppContext (void)
  297. {
  298.     long pid = Nlm_GetAppProcessID();
  299.     AppContext *p1, *p2;
  300.     
  301.     /*
  302.      *    Scan the list for the context of the current app
  303.      */
  304.     for (p1=g_appList,p2=NULL; p1; p1=p1->next)
  305.     {
  306.         if (p1->pid == pid) break;
  307.         p2 = p1;
  308.     }
  309.     /*
  310.      *    Adjust links and release memory 
  311.      */
  312.     if (p1 != NULL)
  313.     {
  314.         if (p2 == NULL)
  315.             g_appList = p1->next;
  316.         else
  317.             p2->next = p1->next;
  318.             
  319.         delete_AppContext(p1);
  320.     }
  321. }
  322.  
  323.  
  324.  
  325. /*    ----------------------------------------------------------------------
  326.  *    SetAppProperty -- Sets a data item int the application context's 
  327.  *        property list, replacing the existing one or creating a new
  328.  *        one if no property with that key exists.
  329.  *
  330.  *    Parameters:
  331.  *        key:        key identifying the property
  332.  *        value:        pointer to arbitrary data
  333.  *
  334.  *    Return value:    
  335.  *        Previous value of the property, if any, or NULL otherwise.
  336.  *
  337.  *    Created: 
  338.  *        06-08-93    Schuler
  339.  *    Modified:
  340.  *        00-00-00    YourName    What changes did you make?
  341.  *    ----------------------------------------------------------------------    */
  342.  
  343. void * LIBCALL Nlm_SetAppProperty (const char *key, void *data)
  344. {
  345.     if (key && *key)
  346.     {
  347.         AppContext *context = GetAppContext();
  348.         AppProperty *p1, *p2, *prop;
  349.         void *prev;
  350.         int d;
  351.         
  352.         for (p1=context->proplist, p2=NULL; p1; p1=p1->next)
  353.         {
  354.             d = strcmp(key,p1->key);
  355.             if (d < 0)  break;
  356.             if (d==0)
  357.             {
  358.                 prev = p1->data;
  359.                 p1->data = data;
  360.                 return prev;    /* previous value */
  361.             }
  362.             p2 = p1;
  363.         }
  364.         
  365.         /*
  366.          *    If we reach here, a property with the given key does not exist, so 
  367.          *    let's create a new one and link it into the list.
  368.          */
  369.         
  370.         if (AppContext_IsLocked(context))
  371.         {
  372.             TRACE("SetAppProperty:  ** property list is locked **\n");
  373.         }
  374.         else
  375.         {        
  376.             AppContext_Lock(context);
  377.             if ((prop = new_AppProperty(key,data)) != NULL)
  378.             {
  379.                 if (p2 == NULL)     
  380.                     context->proplist = prop;
  381.                 else  
  382.                     p2->next = prop;    
  383.                 prop->next = p1;
  384.             }
  385.             AppContext_Unlock(context);
  386.         }
  387.     }    
  388.     return NULL;    /* no previous value */
  389. }
  390.  
  391.  
  392.  
  393. /*    ----------------------------------------------------------------------
  394.  *    GetAppProperty -- Retrieves data value that was set with SetAppProperty.
  395.  *
  396.  *    Parameters:
  397.  *        key:    key identifying the property
  398.  *
  399.  *    Return value:    
  400.  *        Value that was set with SetAppProperty or NULL if no property with 
  401.  *        that key exists.
  402.  *
  403.  *    Created: 
  404.  *        06-08-93    Schuler
  405.  *    Modified:
  406.  *        00-00-00    YourName    What changes did you make?
  407.  *
  408.  *    ----------------------------------------------------------------------    */
  409.  
  410. void * LIBCALL Nlm_GetAppProperty (const char *key)
  411. {
  412.     if (key && *key)
  413.     {
  414.         AppContext *context = GetAppContext();
  415.         AppProperty *prop;
  416.         
  417.         for (prop=context->proplist; prop; prop=prop->next)
  418.         {
  419.             if (strcmp(prop->key,key) ==0)
  420.                 return prop->data;
  421.         }
  422.     }
  423.     return NULL;
  424. }
  425.  
  426.  
  427.  
  428. /*    ----------------------------------------------------------------------
  429.  *    RemoveAppProperty -- Removes a propery from the application context's
  430.  *        property list (if it exists) and returns the data value that was
  431.  *        set with SetAppParam().
  432.  *
  433.  *    Parameters:
  434.  *        key:    key identifying the property
  435.  *
  436.  *    Return value:    
  437.  *        Value that was set with SetAppProperty or NULL if no property with 
  438.  *        that key exists.
  439.  *
  440.  *    Notes:
  441.  *        It is the responsibiliy of the caller to free whatever resources 
  442.  *        the property's data (return value) may happen to point to.
  443.  *
  444.  *    Created: 
  445.  *        06-08-93    Schuler
  446.  *    Modified:
  447.  *        00-00-00    YourName    What changes did you make?
  448.  *
  449.  *    ----------------------------------------------------------------------    */
  450.  
  451. void * LIBCALL Nlm_RemoveAppProperty (const char *key)
  452. {
  453.     if (key && *key)
  454.     {
  455.         AppContext *context = GetAppContext();
  456.         
  457.         if (AppContext_IsLocked(context))
  458.         {
  459.             TRACE("RemoveAppProperty:  ** property list is locked **\n");
  460.         }
  461.         else
  462.         {
  463.             AppProperty *p1, *p2;
  464.             int d;
  465.             
  466.             AppContext_Lock(context);
  467.             for (p1=context->proplist, p2=NULL; p1; p1=p1->next)
  468.             {
  469.                 d = strcmp(key,p1->key);
  470.                 if (d < 0)  break;
  471.                 if (d==0)
  472.                 {
  473.                     void *data = p1->data;
  474.                     if (p2 == NULL)
  475.                         context->proplist = p1->next;
  476.                     else
  477.                         p2->next = p1->next;
  478.                     delete_AppProperty(p1);
  479.                     AppContext_Unlock(context);
  480.                     return data;    /* success */
  481.                 }
  482.                 p2 = p1;
  483.             }
  484.             AppContext_Unlock(context);
  485.         }
  486.     }
  487.     return NULL;    /* failure */        
  488. }
  489.  
  490.  
  491.  
  492. /*    ----------------------------------------------------------------------
  493.  *    EnumAppProperties -- Enumerates all application properties, calling
  494.  *        a caller-supplied callback function with the key and data for
  495.  *        each one.
  496.  *
  497.  *    Parameters:
  498.  *        Pointer to the enumeration callback procedure.
  499.  *
  500.  *    Return value:
  501.  *        Number of properties enumerated.
  502.  *
  503.  *    Callback function:
  504.  *
  505.  *        int LIBCALLBACK MyEmumProc (const char *key, void *value)
  506.  *        {
  507.  *            //--- insert your code here ---
  508.  *
  509.  *            // for example:
  510.  *            if (strcmp(key,"MyBigBuffer") ==0)
  511.  *            {
  512.  *                SetAppProperty(key,NULL);
  513.  *                MemFree(data)
  514.  *                return FALSE;    // FALSE to stop enumeration at this point
  515.  *            }
  516.  *            return TRUE;        // TRUE to continue the enumeration.
  517.  *        }
  518.  *
  519.  *    Notes:
  520.  *        It is OK to call SetAppProperty() from within the callback function,
  521.  *        but _only_ to change the value of an existing property.  Any attempt 
  522.  *        to alter the property list, either by calling SetAppProperty() with 
  523.  *        a new key or calling RemoveAppProperty() will fail while an enumera-
  524.  *        tion is in progress.
  525.  *
  526.  *    Created: 
  527.  *        06-09-93    Schuler
  528.  *    Modified:
  529.  *        00-00-00    YourName    What changes did you make?
  530.  *
  531.  *    ----------------------------------------------------------------------    */
  532.  
  533. int LIBCALL Nlm_EnumAppProperties (Nlm_AppPropEnumProc proc)
  534. {
  535.     int count = 0;
  536.     if (proc != NULL)
  537.     {
  538.         AppContext *context = GetAppContext();
  539.         AppProperty *prop;
  540.         
  541.         if (context->enums==0)
  542.             AppContext_Lock(context);
  543.         context->enums++;
  544.         for (prop=context->proplist; prop; prop=prop->next)
  545.         {
  546.             count ++;
  547.             if ( ! (*proc)(prop->key,prop->data) )
  548.                 break;
  549.         }
  550.         context->enums--;
  551.         if (context->enums==0)
  552.             AppContext_Unlock(context);
  553.     }
  554.     return count;
  555. }
  556.  
  557.  
  558.  
  559. /*    ----------------------------------------------------------------------
  560.  *    GetAppProcessID  [Schuler, 06-04-93]
  561.  *
  562.  *    Returns an identifier for the current application instance.
  563.  *
  564.  *    Notes:
  565.  *    On the Macintosh, the process ID is a 64-bit value, which is being
  566.  *    condensed down to 32-bits here by XORing the high and low halves
  567.  *    of the value.  I can't guarantee it will be unique (although it
  568.  *    seems to be in practice), but this code is not being dynamically
  569.  *    linked on the Mac, so it doesn't matter.
  570.  *
  571.  *    MODIFICATIONS
  572.  *    04-10-93  Schuler  Added Macintosh version.
  573.  *    12-16-93  Schuler  Added Borland version contributed by M.Copperwhite
  574.  *    ----------------------------------------------------------------------    */
  575.  
  576. #define USE_GETPID
  577.  
  578. /* (insert other platform-specific versions here as necessary and #undef USE_GETPID) */
  579.  
  580.  
  581. /* ----- Macintosh Version ----- */
  582. #ifdef OS_MAC
  583. #include <Processes.h>
  584. #include <GestaltEqu.h>
  585.  
  586. long LIBCALL Nlm_GetAppProcessID (void)
  587. {
  588.     long gval;
  589.     ProcessSerialNumber psn;    /* a 64-bit value*/
  590.     
  591.     if (Gestalt (gestaltSystemVersion, &gval) == noErr && (short) gval >= 7 * 256) {
  592.         GetCurrentProcess(&psn);    
  593.         return (psn.highLongOfPSN ^ psn.lowLongOfPSN);    /* merge to 32-bits */
  594.     } else {
  595.         return 1;
  596.     }
  597. }
  598.  
  599. #undef USE_GETPID
  600. #endif
  601.  
  602.  
  603. /* ----- NCBIDLL mod Borland DLL version - call Windows API to get PSP ----- */
  604. #ifdef _WINDLL
  605. #ifdef COMP_BOR
  606.  
  607. long LIBCALL Nlm_GetAppProcessID (void)
  608. {
  609.   return GetCurrentPDB();
  610. }
  611.  
  612. #undef USE_GETPID
  613. #endif
  614. #endif
  615.  
  616.  
  617. /* ----- Generic Version ----- */
  618. #ifdef USE_GETPID
  619. #if defined(COMP_MSC) || defined(COMP_BOR)
  620. #include <process.h>
  621. #ifdef COMP_CWI
  622. #define getpid     _getpid
  623. #endif
  624. #endif
  625.  
  626. long LIBCALL Nlm_GetAppProcessID (void)
  627. {
  628. #ifdef COMP_CWI
  629.     return 0;
  630. #else
  631.     return getpid();
  632. #endif
  633. }
  634.  
  635. #endif
  636.  
  637.  
  638.